/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package main.pso;

import main.Centroid;
import main.DataVector;
import main.Particle;
import main.Util;
import main.Velocity;

/**
 *
 * @author Amigao
 */
public class SimpleKMeans extends PSO{

    public SimpleKMeans(String fileName){
        super(fileName);
    }

    @Override
    public void execute(int k, int numberOfParticles, int numberOfIterations) {

        this.euclidianDistances = new double[k];

		this.initializeTrainingSet();

        this.globalBestPosition = this.getGlobalBestPositionByKMeans(k);

        for (DataVector trainningData : trainningSet) {

            for (int j = 0; j < globalBestPosition.getCentroids().length; j++) {
                this.euclidianDistances[j] = Util
                        .calculateEuclidianDistance(trainningData,
                                globalBestPosition.getCentroids()[j]);
            }

            this.assignTrainningDataToNearestCentroid(trainningData,
                    globalBestPosition);

        }
        this.evaluate(k, globalBestPosition);
    }
public Particle getGlobalBestPositionByKMeans(int k) {

		Particle kmeansResult = new Particle(0, k);
		Centroid centroid = null;
		Velocity velocity = null;
		// primeiro passo, iniciar a particula de resultado com os primeiros
		// elementos da base
		for (int i = 0; i < k; i++) {

			centroid = new Centroid(i,
					this.trainningSet.get(0).getPosition().length);
			velocity = new Velocity(
					this.trainningSet.get(0).getPosition().length);

			for (int l = 0; l < centroid.getPosition().length; l++) {
				centroid.getPosition()[l] = this.trainningSet.get(i)
						.getPosition()[l];
				velocity.getVelocities()[l] = Math.random();
			}
			kmeansResult.getCentroids()[i] = centroid;
			kmeansResult.getVelocities()[i] = velocity;

		}
		// vetor que vai guardar as diastancias entre os centroides
		euclidianDistances = new double[k];

		for (DataVector dataVector : trainningSet) {

			for (int j = 0; j < kmeansResult.getCentroids().length; j++) {
				this.euclidianDistances[j] = Util.calculateEuclidianDistance(
						dataVector, kmeansResult.getCentroids()[j]);
			}

			this.assignTrainningDataToNearestCentroid(dataVector, kmeansResult);
		}

		Particle testParticle = kmeansResult.clone();

		this.recalculateCentroid(kmeansResult);

		boolean convergency = false;
		while (!convergency) {

			this.recalculateCentroid(kmeansResult);
			// kmeansResult = null;
			for (DataVector dataVector : trainningSet) {

				for (int j = 0; j < kmeansResult.getCentroids().length; j++) {
					this.euclidianDistances[j] = Util
							.calculateEuclidianDistance(dataVector,
									kmeansResult.getCentroids()[j]);
				}

				this.assignTrainningDataToNearestCentroid(dataVector,
						kmeansResult);

			}

			// agora s� falta testar se convergiu...
			convergency = this.hasConverged(testParticle, kmeansResult);

			testParticle = kmeansResult.clone();

		}
		kmeansResult.calculateFitness();
		return kmeansResult;
	}

    protected boolean hasConverged(Particle testParticle, Particle kmeansResult) {
		double somaDasDiferencas = 0.0;
		for (int i = 0; i < testParticle.getCentroids().length; i++) {
			somaDasDiferencas = Util.calculateEuclidianDistance(kmeansResult
					.getCentroids()[i], testParticle.getCentroids().clone()[i]);
		}
		if (somaDasDiferencas == 0) {
			return true;
		}
		return false;
	}

    @Override
    public void initializeParticles(int k, int numberOfParticles) {
        
    }
}
